package com.cnap.service.impl;

import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.cnap.db.entity.FileInfoPO;
import com.cnap.db.entity.MicroServicePO;
import com.cnap.db.entity.PatchInfoPO;
import com.cnap.db.entity.ProgressPO;
import com.cnap.db.mapper.FileMapper;
import com.cnap.db.mapper.MicroServiceMapper;
import com.cnap.db.mapper.ProgressMapper;
import com.cnap.model.exception.JsonException;
import com.cnap.model.file.FileConstants;
import com.cnap.model.file.PatchStatusRes;
import com.cnap.model.progress.ProgressConstants;
import com.cnap.model.progress.ProgressVO;
import com.cnap.model.progress.ProgressVOForSplit;
import com.cnap.model.schedule.MicroServiceVOForSplit;
import com.cnap.service.ApplicationService;
import com.cnap.service.ProgressService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * <类文件描述>
 *
 * @author xc
 **/
@Service
public class ProgressServiceImpl implements ProgressService {

    private static final Logger LOGGER = LoggerFactory.getLogger(ProgressServiceImpl.class);

    private final ProgressMapper progressMapper;
    private final FileMapper fileMapper;
    private final MicroServiceMapper microServiceMapper;

    @Autowired
    public ProgressServiceImpl(ProgressMapper progressMapper, FileMapper fileMapper, MicroServiceMapper microServiceMapper) {
        this.progressMapper = progressMapper;
        this.fileMapper = fileMapper;
        this.microServiceMapper = microServiceMapper;
    }

    /**
     * 根据id查询进度
     *
     * @param id id
     * @return 结果
     */
    @Override
    public ProgressVO getProgressByApplicationId(String id) {
        ProgressPO progressPO = progressMapper.selectProgressById(id);
        if (Objects.isNull(progressPO)) {
            LOGGER.error("can't find progress, id={}", id);
            throw new JsonException(500, "未找到该应用上传进度");
        }
        // 有异常
        if (CharSequenceUtil.isNotBlank(progressPO.getException())) {
            // 异常时，需要删除该应用的信息
            LOGGER.error("catch exception={}, try to delete all resources, id={}", progressPO.getException(), id);
            ApplicationService applicationService = SpringUtil.getBean(ApplicationService.class);
            applicationService.deleteAllUploadResourcesByApplicationId(id);
            throw new JsonException(500, progressPO.getException());
        }
        List<PatchInfoPO> patchInfoPOS = fileMapper.selectByParentId(id);
        // 转换
        List<PatchStatusRes> patchStatusRes = patchInfoPOS.stream().map(patchInfoPO -> {
            PatchStatusRes statusRes = new PatchStatusRes();
            statusRes.setId(patchInfoPO.getId());
            statusRes.setIndex(patchInfoPO.getIndex());
            statusRes.setStatus(patchInfoPO.getStatus());
            return statusRes;
        }).collect(Collectors.toList());
        // 组装vo
        ProgressVO progressVO = new ProgressVO();
        progressVO.setId(id);
        progressVO.setException(progressPO.getException());
        progressVO.setPercent(progressPO.getPercent());
        progressVO.setStage(progressPO.getStage());
        progressVO.setPatchStatus(patchStatusRes);
        return progressVO;
    }

    /**
     * 根据id查询进度
     *
     * @param id id
     * @return 结果
     */
    @Override
    public ProgressPO getProgressPOByApplicationId(String id) {
        ProgressPO progressPO = progressMapper.selectProgressById(id);
        if (Objects.isNull(progressPO)) {
            LOGGER.error("can't find progress, id={}", id);
            throw new JsonException(500, "未找到该应用上传进度");
        }
        return progressPO;
    }

    /**
     * 根据id查询分解微服务进度
     *
     * @param id id
     * @return 结果
     */
    @Override
    public ProgressVOForSplit getProgressForSplitByApplicationId(String id) {
        ProgressPO progressPO = progressMapper.selectProgressById(id);
        if (Objects.isNull(progressPO)) {
            LOGGER.error("can't find progress, id={}", id);
            throw new JsonException(500, "该应用未分解，无法获取进度");
        }
        // 有异常
        if (CharSequenceUtil.isNotBlank(progressPO.getException())) {
            String exp = progressPO.getException();
            // 异常时，需要删除该应用的信息
            LOGGER.error("catch exception, id={}", id);
            if (ProgressConstants.TYPE_SPLIT.equals(progressPO.getType())) {
                // 拆解时出现错误，需要保留zip包
                // 删除unzip和分解出来的正常的微服务信息
                ApplicationService applicationService = SpringUtil.getBean(ApplicationService.class);
                applicationService.deleteUnzipFileAndDbInfo(id);
                // 重置进度条到已上传100，未分解的状态
                progressPO.setType(ProgressConstants.TYPE_UPLOAD);
                progressPO.setPercent(100);
                progressPO.setStage(ProgressConstants.STAGE_UPLOAD_MERGE);
                progressPO.setException("");

                updateProgress(progressPO);
            }
            throw new JsonException(500, exp);
        }
        List<MicroServicePO> microServicePOS = microServiceMapper.selectMicroServiceByAppId(id);
        List<MicroServiceVOForSplit> microServices = microServicePOS.stream().map(po -> {
            MicroServiceVOForSplit microService = new MicroServiceVOForSplit();
            // id
            microService.setId(po.getId());
            // 服务名称
            microService.setServiceName(po.getMicroServiceName());
            // 应用名称
            microService.setApplicationName(po.getApplicationName());
            // 大小
            microService.setSize(po.getSize());
            // 更新时间
            microService.setUpdateTime(po.getUpdateTime());
            // 云商
            microService.setProvider(po.getUserName());
            return microService;
        }).collect(Collectors.toList());
        ProgressVOForSplit progressVOForSplit = new ProgressVOForSplit();
        // id
        progressVOForSplit.setId(progressPO.getId());
        // 步骤
        progressVOForSplit.setStage(progressPO.getStage());
        // 进度
        progressVOForSplit.setPercent(progressPO.getPercent());
        // 微服务信息
        progressVOForSplit.setMicroServices(microServices);
        return progressVOForSplit;
    }

    /**
     * 根据id删除进度信息
     *
     * @param id id
     */
    @Override
    public void deleteProgressByApplicationId(String id) {
        progressMapper.deleteProgressById(id);
    }

    /**
     * 保存进度
     *
     * @param progressPO 进度
     * @return 结果
     */
    @Override
    public boolean initProgress(ProgressPO progressPO) {
        ProgressPO progressPO1 = progressMapper.selectProgressById(progressPO.getId());
        if (Objects.nonNull(progressPO1)) {
            if (progressPO1.equals(progressPO)) {
                // 重复创建
                LOGGER.info("progress is same, just return true, {}", progressPO);
                return true;
            } else {
                // 更新
                LOGGER.warn("progress has been add, try to update, {}", progressPO);
                return progressMapper.updateProgress(progressPO) == 1;
            }
        }
        LOGGER.info("save new progress, {}", progressPO);
        return progressMapper.saveProgress(progressPO) == 1;
    }

    /**
     * 更新进度
     *
     * @param progressPO 进度信息
     * @return 结果
     */
    @Override
    public boolean updateProgress(ProgressPO progressPO) {
        ProgressPO old = progressMapper.selectProgressById(progressPO.getId());
        if (Objects.isNull(old)) {
            LOGGER.error("can't find progress, {}", progressPO);
            return false;
        }
        return progressMapper.updateProgress(progressPO) == 1;
    }

    /**
     * 更新进度
     *
     * @param id      id
     * @param percent 进度
     * @return 结果
     */
    @Override
    public boolean updateProgressPercent(String id, int percent) {
        ProgressPO progressPO = new ProgressPO();
        progressPO.setId(id);
        progressPO.setPercent(percent);

        return progressMapper.updateProgress(progressPO) == 1;
    }

    /**
     * 更新异常
     *
     * @param id        id
     * @param exception 异常
     * @return 结果
     */
    @Override
    public boolean updateProgressException(String id, String exception) {
        ProgressPO progressPO = new ProgressPO();
        progressPO.setId(id);
        progressPO.setException(exception);
        // 有异常时，将进度重置
        progressPO.setPercent(0);
        // 有异常时，将分片上传至为失败
        fileMapper.updatePatchInfoStatusByParentId(id, FileConstants.PATCH_STATUS_FAILED);

        return progressMapper.updateProgress(progressPO) == 1;
    }

    /**
     * 查询进度
     *
     * @param id id
     * @return 进度
     */
    @Override
    public int getPercentByApplicationId(String id) {
        ProgressPO progressPO = progressMapper.selectProgressById(id);
        return progressPO.getPercent();
    }

    /**
     * 计算分片阶段的进度，当前进度加一个分片
     *
     * @param applicationId 应用id
     */
    @Override
    public void calPercentWithOnePatchAndUpdate(String applicationId) {
        List<PatchInfoPO> patchInfos = fileMapper.selectByParentId(applicationId);
        FileInfoPO fileInfoPO = fileMapper.selectById(applicationId);
        int totalPatchNum = fileInfoPO.getPatchNums();
        // 查询当前进度
        ProgressPO currentProgress = progressMapper.selectProgressById(applicationId);
        // 新的进度
        int newPatchPercent = (ProgressConstants.UPLOAD_PATCH_PERCENT * patchInfos.size()) / totalPatchNum;
        if (newPatchPercent < currentProgress.getPercent()) {
            // 有问题
            LOGGER.warn("new patch percent is less than current percent, new={}, current={}", newPatchPercent,
                    currentProgress.getPercent());
        } else {
            // 更新进度
            currentProgress.setPercent(newPatchPercent);
            updateProgress(currentProgress);
        }

    }
}
